package com.googlecode.xmlsorter4diff;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

/*
 * XML Sorter for Diff
 */
public class XMLSorterForDiff {

	private static ElementComparator c = new ElementComparator();

	/**
	 * Sorts the file.
	 * 
	 * @param pReadFile
	 */
	private static void sort(String pReadFile, String pWriteFile) {

		try {
			File f = new File(pReadFile);
			FileInputStream fis = new FileInputStream(f);
			InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
			BufferedReader br = new BufferedReader(isr);

			SAXBuilder builder = new SAXBuilder();
			Document doc = builder.build(br);
			Element root = doc.getRootElement();
			iterateElements(root, 0);
			doc.setRootElement(root);

			try {
				FileOutputStream out = new FileOutputStream(pWriteFile);
				XMLOutputter serializer = new XMLOutputter(Format
						.getPrettyFormat());
				serializer.output(doc, out);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}

		} catch (FileNotFoundException e) {
			System.out.println("error reading file: " + pReadFile);
			e.printStackTrace();
		} catch (IOException e) {
			System.out.println("IOException: " + e.getMessage());
			e.printStackTrace();
		} catch (JDOMException e) {
			System.out.println("file is probably not valid XML: " + pReadFile);
			e.printStackTrace();
		} catch (Exception e) {
			System.out.println("Exception: " + e.getMessage());
			e.printStackTrace();
		}

	}

	/**
	 * Recursive iteration of elements.
	 * 
	 * @param pParent
	 * @param pLevel
	 */
	private static void iterateElements(Element pParent, int pLevel) {
		// System.out.println("i: " + pLevel);
		if (pLevel == 0)
			sortElements(pParent);
		ArrayList<Element> al = new ArrayList<Element>();
		al.addAll(pParent.getChildren());
		if (al.size() > 0) {
			for (int j = 0; j < al.size(); j++) {
				Element e = al.get(j);
				sortElements(e);
				e.detach();
				iterateElements(e, pLevel + 1);
			}
			pParent.setContent(al);
		}
	}

	/**
	 * Sorts the children of an jdom element.
	 * 
	 * @param pParent
	 *            Parent element.
	 */
	private static void sortElements(Element pParent) {
		List<Element> children = new ArrayList<Element>(pParent.getChildren());
		Collections.sort(children, c);
		ListIterator<Element> childrenIter = children.listIterator();

		List<Element> newContent = new ArrayList<Element>(pParent.getContent());
		ListIterator<Element> contentIter = newContent.listIterator();

		while (contentIter.hasNext()) {
			Object o = contentIter.next();
			if (o instanceof Element) {
				contentIter.set(childrenIter.next());

			}
		}

		pParent.setContent((Collection<Element>) null);
		pParent.setContent(newContent);
	}

	public static void main(final String[] args) {
		File file = new File(args[0]);
		String readFile = file.getAbsolutePath();
		String writeFile = file.getAbsolutePath().substring(0,
				file.getAbsolutePath().lastIndexOf(".")).concat(
				"-sorted"
						+ file.getAbsolutePath().substring(
								file.getAbsolutePath().lastIndexOf(".")));
		System.out.println("read file: " + readFile);
		System.out.println("write file: " + writeFile);
		sort(readFile, writeFile);
	}

}
